#include "sdmp_cmd_lookup.h"
#include <string.h>
#include <stdlib.h>

/* 定义命令字符串 */
#define SDMP_KEY_REGISTER       "register"
#define SDMP_KEY_KEEPALIVE      "keepAlive"
#define SDMP_KEY_TRANSDOWN      "transDown"
#define SDMP_KEY_TRANSUP        "transUp"

/* 命令编码与字符串的映射数组 */
static sdmp_cmd_code_str_t sdmp_cmd_code_str_array[] = {
    {SDMP_CMD_CODE_TRANSUP,     SDMP_KEY_TRANSUP},
    {SDMP_CMD_CODE_REGISTER,    SDMP_KEY_REGISTER},
    {SDMP_CMD_CODE_KEEPALIVE,   SDMP_KEY_KEEPALIVE},
    {SDMP_CMD_CODE_TRANSDOWN,   SDMP_KEY_TRANSDOWN},
};

/* 哈希表节点结构 */
struct sdmp_cmd_node {
    struct hlist_node hnode;    // hlist 节点
    sdmp_cmd_code_t code;       // 命令编码
    char *str;                  // 命令字符串
};

/* 哈希表大小 */
#define SDMP_HASH_SIZE 16

/* 哈希表 */
static struct hlist_head sdmp_cmd_hash[SDMP_HASH_SIZE];

/* 哈希函数 */
static unsigned int sdmp_hash(const char *str) {
    unsigned int hash = 0;
    while (*str) {
        hash = (hash << 5) + hash + *str++;
    }
    return hash % SDMP_HASH_SIZE;
}

/* hlist 初始化 */
static void hlist_init(struct hlist_head *h) {
    h->head = NULL;
}

/* hlist 添加节点到头部 */
static void hlist_add_head(struct hlist_node *n, struct hlist_head *h) {
    struct hlist_node *first = h->head;
    n->next = first;
    if (first)
        first->pprev = &n->next;
    h->head = n;
    n->pprev = &h->head;
}

/* hlist 删除节点 */
static void hlist_del(struct hlist_node *n) {
    struct hlist_node *next = n->next;
    struct hlist_node **pprev = n->pprev;
    *pprev = next;
    if (next)
        next->pprev = pprev;
}

/* 初始化哈希表 */
int sdmp_cmd_lookup_init(void) {
    size_t i;

    /* 初始化哈希表 */
    for (i = 0; i < SDMP_HASH_SIZE; i++) {
        hlist_init(&sdmp_cmd_hash[i]);
    }

    /* 将数组元素插入哈希表 */
    for (i = 0; i < sizeof(sdmp_cmd_code_str_array) / sizeof(sdmp_cmd_code_str_array[0]); i++) {
        struct sdmp_cmd_node *node = malloc(sizeof(struct sdmp_cmd_node));
        if (!node) {
            /* 清理已分配的节点 */
            sdmp_cmd_lookup_destroy();
            return -1;
        }

        node->code = sdmp_cmd_code_str_array[i].code;
        node->str = strdup(sdmp_cmd_code_str_array[i].str);
        if (!node->str) {
            free(node);
            sdmp_cmd_lookup_destroy();
            return -1;
        }

        unsigned int index = sdmp_hash(node->str);
        hlist_add_head(&node->hnode, &sdmp_cmd_hash[index]);
    }

    return 0;
}

/* 查找命令编码 */
sdmp_cmd_code_t sdmp_cmd_code_lookup(const char *cmd_str) {
    if (!cmd_str) {
        return SDMP_CMD_CODE_UNKNOWN;
    }

    unsigned int index = sdmp_hash(cmd_str);
    struct hlist_node *pos;
    struct sdmp_cmd_node *node;

    /* 遍历哈希桶中的链表 */
    for (pos = sdmp_cmd_hash[index].head; pos; pos = pos->next) {
        node = (struct sdmp_cmd_node *)((char *)pos - offsetof(struct sdmp_cmd_node, hnode));
        if (strcmp(node->str, cmd_str) == 0) {
            return node->code;
        }
    }

    return SDMP_CMD_CODE_UNKNOWN;
}

/* 清理哈希表 */
void sdmp_cmd_lookup_destroy(void) {
    size_t i;
    struct hlist_node *pos, *next;

    for (i = 0; i < SDMP_HASH_SIZE; i++) {
        pos = sdmp_cmd_hash[i].head;
        while (pos) {
            next = pos->next;
            struct sdmp_cmd_node *node = (struct sdmp_cmd_node *)((char *)pos - offsetof(struct sdmp_cmd_node, hnode));
            hlist_del(&node->hnode);
            free(node->str);
            free(node);
            pos = next;
        }
        sdmp_cmd_hash[i].head = NULL;
    }
}